﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using MouseKeyboardLibrary;

namespace SampleApplication
{
    public partial class HookTestForm : Form
    {

        //TODO make private again
        public MouseHook mouseHook = new MouseHook();
        KeyboardHook keyboardHook = new KeyboardHook();
        public bool gestureFormShown = false;

        //TODO: delete
        Form1 form1;

        public HookTestForm()
        {
            InitializeComponent();

            //TODO: delete
            form1 = new Form1(this,new Point(0,0),MouseButtons.None); //todo: refactor passing in point
        }

        private void TestForm_Load(object sender, EventArgs e)
        {
            //register mouse events of this form with the mouse hook

            mouseHook.MouseMove += new MouseEventHandler(mouseHook_MouseMove);
            mouseHook.MouseDown += new MouseEventHandler(mouseHook_MouseDown);
            mouseHook.MouseUp += new MouseEventHandler(mouseHook_MouseUp);
            mouseHook.MouseWheel += new MouseEventHandler(mouseHook_MouseWheel);

            keyboardHook.KeyDown += new KeyEventHandler(keyboardHook_KeyDown);
            keyboardHook.KeyUp += new KeyEventHandler(keyboardHook_KeyUp);
            keyboardHook.KeyPress += new KeyPressEventHandler(keyboardHook_KeyPress);

            mouseHook.Start();
            keyboardHook.Start();

            SetXYLabel(MouseSimulator.X, MouseSimulator.Y);

        }

        void keyboardHook_KeyPress(object sender, KeyPressEventArgs e)
        {

            AddKeyboardEvent(
                "KeyPress",
                "",
                e.KeyChar.ToString(),
                "",
                "",
                ""
                );

        }

        void keyboardHook_KeyUp(object sender, KeyEventArgs e)
        {

            AddKeyboardEvent(
                "KeyUp",
                e.KeyCode.ToString(),
                "",
                e.Shift.ToString(),
                e.Alt.ToString(),
                e.Control.ToString()
                );

        }

        void keyboardHook_KeyDown(object sender, KeyEventArgs e)
        {


            AddKeyboardEvent(
                "KeyDown",
                e.KeyCode.ToString(),
                "",
                e.Shift.ToString(),
                e.Alt.ToString(),
                e.Control.ToString()
                );

        }

        void mouseHook_MouseWheel(object sender, MouseEventArgs e)
        {

            AddMouseEvent(
                "MouseWheel",
                "",
                "",
                "",
                e.Delta.ToString()
                );

        }

        void mouseHook_MouseUp(object sender, MouseEventArgs e)
        {

                AddMouseEvent(
                    "MouseUp",
                    e.Button.ToString(),
                    e.X.ToString(),
                    e.Y.ToString(),
                    ""
                    );

        }

        bool isClickOutsideForm(MouseEventArgs e)
        {
            //if the form is not showing then the click is outside of the form
            if (this.form1 == null || this.form1.IsDisposed)
            {
                Console.WriteLine("Form is not showing, click is outside of form.");
                return true;
            }

            Point formStart = this.form1.Location;
            Point formEnd = new Point(formStart.X + this.form1.Width, formStart.Y + this.form1.Height);

            if (e.Location.X < formStart.X
                || e.Location.Y < formStart.Y
                || e.Location.X >= formEnd.X
                || e.Location.Y >= formEnd.Y) //TODO: verify should this be > or >= ?
            {
                return true;
            }
            return false;
        }

        void mouseHook_MouseDown(object sender, MouseEventArgs e)
        {
            //if (gestureFormShown == false)
            
            //check if the form is NOT shown
            //or
            //if the form is shown but the click is outside of the form

            //if (this.isClickOutsideForm(e) || gestureFormShown == false)
            if (gestureFormShown == false || this.isClickOutsideForm(e))
            {

                //if (e.Button == System.Windows.Forms.MouseButtons.Right)
                if (e.Button == System.Windows.Forms.MouseButtons.Right
                    || e.Button == System.Windows.Forms.MouseButtons.Left)
                {


                    if (form1 == null || form1.IsDisposed)
                    {
                        form1 = new Form1(this, e.Location,e.Button);
                    }

                    //center the form at the mouse click point
                    SetFormStartLocation(e);
  
                    form1.mouseEventPoint = e.Location; //TODO: refactor
                    form1.mouseButton = e.Button;
                    ////draw a circle at the mouse click point
                    //form1.drawCircleAtMouseEventPoint(); //TODO: refactor
                    //form1.Invalidate();

                    Console.WriteLine("form1 loc: " + form1.Location);
                    form1.BringToFront();
                    form1.TopMost = true;
                    form1.Show();
                    //form1.ShowDialog(); //causes a delay
                    this.gestureFormShown = true;

                    //mouseHook.Stop();

                    //mousehook is restarted in form


                    //form1.ShowDialog(); //dialog seems to really slow it down for some reason

                    //TODO: refactor

                    //don't restart the mousehook until the form is gone?
                    //if (form1 == null || form1.IsDisposed || !form1.Visible)
                    //{
                    //    mouseHook.Start();
                    //}

                    //mouseHook.Start();
                }

                AddMouseEvent(
                    "MouseDown",
                    e.Button.ToString(),
                    e.X.ToString(),
                    e.Y.ToString(),
                    ""
                    );

                //Console.WriteLine("Mesage after: sorry no right clicks allowed, Pos: " + e.Location);

                //just having this slows it down?
                //if (e.Button == System.Windows.Forms.MouseButtons.Right)
                //{
                //    MessageBox.Show("Mesage after: sorry no right clicks allowed");
                //}

            }//end if processed
        }

        private void SetFormStartLocation(MouseEventArgs e)
        {
            //center the form at the click location
            form1.StartPosition = FormStartPosition.Manual;
            form1.Location = new Point(e.Location.X - (int)(0.5 * form1.Width), e.Location.Y - (int)(0.5 * form1.Height));
        
            //make sure that the entire form can be seen on screen

            Point formTopLeft = form1.Location; //screen coords
            Point formBottomRight = new Point(formTopLeft.X + form1.Width, formTopLeft.Y + form1.Height);

            int formLeft = form1.Location.X; //screen coords
            int formRight = formLeft + form1.Width;
            int formTop = form1.Location.Y; //screen coords
            int formBottom = formTop + form1.Height;

            Console.WriteLine("form left: " + formLeft);
            Console.WriteLine("form right: " + formRight);
            Console.WriteLine("form top: " + formTop);
            Console.WriteLine("form bottom: " + formBottom);

            //only for the main screen at the moment
            //TODO: add support for multiple monitors?
            int screenLeft = Screen.PrimaryScreen.Bounds.Left;
            int screenRight = Screen.PrimaryScreen.Bounds.Right;
            int screenTop = Screen.PrimaryScreen.Bounds.Top;
            int screenBottom = Screen.PrimaryScreen.Bounds.Bottom; //using Bounds includes taskbar

            Console.WriteLine("screen left: " + screenLeft);
            Console.WriteLine("screen right: " + screenRight);
            Console.WriteLine("screen top: " + screenTop);
            Console.WriteLine("screen bottom: " + screenBottom);

            //TODO: make more efficient by only setting location at the very end

            if (formLeft < screenLeft)
            {
                form1.Location = new Point(screenLeft, form1.Location.Y);
            }

            if (formTop < screenTop)
            {
                form1.Location = new Point(form1.Location.X, screenTop);
            }

            //TODO: right is only at the primary display
            if (formRight > screenRight)
            {
                form1.Location = new Point(form1.Location.X - (formRight-screenRight), form1.Location.Y);
            }

            if (formBottom > screenBottom)
            {
                form1.Location = new Point(form1.Location.X, form1.Location.Y - (formBottom - screenBottom));
            }

            

        }

        void mouseHook_MouseMove(object sender, MouseEventArgs e)
        {

            SetXYLabel(e.X, e.Y);

        }

        void SetXYLabel(int x, int y)
        {

            curXYLabel.Text = String.Format("Current Mouse Point: X={0}, y={1}", x, y);

        }

        void AddMouseEvent(string eventType, string button, string x, string y, string delta)
        {

            listView1.Items.Insert(0,
                new ListViewItem(
                    new string[]{
                        eventType, 
                        button,
                        x,
                        y,
                        delta
                    }));

        }

        void AddKeyboardEvent(string eventType, string keyCode, string keyChar, string shift, string alt, string control)
        {

            listView2.Items.Insert(0,
                 new ListViewItem(
                     new string[]{
                        eventType, 
                        keyCode,
                        keyChar,
                        shift,
                        alt,
                        control
                }));

        }

        private void TestForm_FormClosed(object sender, FormClosedEventArgs e)
        {

            // Not necessary anymore, will stop when application exits

            //mouseHook.Stop();
            //keyboardHook.Stop();

        }


    }
}
